﻿using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using Zo.Events;

namespace Zo.Logging
{
    /// <summary>
    /// 文本日志记录器。
    /// </summary>
    public class TxtLogger : LoggerBase
    {
        /// <summary>
        /// 初始化。
        /// </summary>
        /// <param name="level">日志级别。</param>
        public TxtLogger(LogLevel level) : base(level)
        {
            EventManager.Instance.Register(new LogEventHandler());
        }

        /// <summary>
        /// 写入日志。
        /// </summary>
        /// <param name="eventType">日志类型。</param>
        /// <param name="message">日志信息。</param>
        /// <param name="args">日志参数。</param>
        protected override void WriteLog(TraceEventType eventType, string message, params object[] args)
        {
            EventManager.Instance.Handle(new TxtLogEvent
            {
                Message = message ?? string.Empty,
                FolderName = GetFolderName(eventType) ?? string.Empty
            });
        }

        /// <summary>
        /// 获得由指定类型转换成的文件夹名称。
        /// </summary>
        /// <param name="eventType">跟踪事件类型。</param>
        /// <returns>文件夹名称。</returns>
        private static string GetFolderName(TraceEventType eventType) => eventType.ToString();
    }

    internal class TxtLogEvent
    {
        public string FolderName { get; set; }

        public string Message { get; set; }
    }

    internal class LogEventHandler : EventHandlerBase<TxtLogEvent>
    {
        private static readonly object _lockObject = new object();

        protected override IEventResult OnHandle(TxtLogEvent envelope)
        {
            var message = envelope.Message;

            var path = Path.Combine(
             AppDomain.CurrentDomain.BaseDirectory, "logs", envelope.FolderName, DateTime.Now.ToString("yyyy"), DateTime.Now.ToString("MM"), DateTime.Now.ToString("dd"));

            //如果日志目录不存在就创建。
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }

            //获取当前系统时间。
            var time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");

            //用日期对日志文件命名。
            var filename = path + "/" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".log";

            WirteFile(path, filename, $"{time}:{message}");

            return new EventResult { Status = true };
        }

        private void WirteFile(string directory, string path, string message)
        {
            try
            {
                lock (_lockObject)
                {
                    using (var streamWriter = File.AppendText(path))
                    {
                        streamWriter.WriteLine(message);
                        streamWriter.Flush();
                    }
                }
            }
            catch (Exception exception)
            {
                path = $"{directory}/{DateTime.Now.ToString("yyyyMMddHHmmssfff")}.error";

                var errorBuilder = new StringBuilder();

                errorBuilder.AppendLine($"写入日志：{message} 过程中出现异常");
                errorBuilder.AppendLine(exception.Message);
                errorBuilder.AppendLine(exception.StackTrace);

                lock (_lockObject)
                {
                    using (var streamWriter = File.AppendText(path))
                    {
                        streamWriter.WriteLine(errorBuilder.ToString());
                        streamWriter.Flush();
                    }
                }
            }
        }
    }
}